//
// Created by Administrator on 2019/12/24.
//

#include <iostream>
using namespace std;

class Parent{
public:
    virtual int getAge(){
        cout<<"parent get age"<<endl;
        return 0;
    }
};

class Child : public Parent{
public:
    int getAge() override {
        cout<<"child get age"<<endl;
        return 1;
    }
};

/**
 * （1）使用场景

在基本数据类型之间转换，如把 int 转换为 char，这种带来安全性问题由程序员来保证；
在有类型指针与 void * 之间转换；
用于类层次结构中基类和派生类之间指针或引用的转换。
上行转换（派生类---->基类）是安全的；
下行转换（基类---->派生类）由于没有动态类型检查，所以是不安全的。


（2）使用特点

主要执行非多态的转换操作，用于代替C中通常的转换操作。
隐式转换都建议使用 static_cast 进行标明和替换。
不能使用 static_cast 在有类型指针内转换。
 */
void testStaticCast()
{
    // 1. 使用static_cast在基本数据类型之间转换
    float fval = 10.12;
    int ival = static_cast<int>(fval);  // float --> int
    cout << ival << endl;  // out: 10

    // 2. 使用static_cast在有类型指针与void *之间转换
    int *intp = &ival;
    void *voidp = static_cast<void *>(intp); // int* --> void*
    // cout << *voidp << endl; // error,voidp的大小未知
    long *longp = static_cast<long *>(voidp);
    cout << *longp << endl; // out: 10

    // 3. 用于类层次结构中基类和派生类之间指针或引用的转换
    // 上行转换（派生类---->基类）是安全的
    Child *tCDerived1 = nullptr;
    Parent *tCBase1 = static_cast<Parent*>(tCDerived1);
    // 下行转换（基类---- > 派生类）由于没有动态类型检查，所以是不安全的
    Parent *tCBase2 = nullptr;
    Child *tCDerived2 = static_cast<Child*>(tCBase2); //不会报错，但是不安全


    // 不能使用static_cast在有类型指针内转换
    float *floatp = &fval;  //10.12的addr
    //int *intp1 = static_cast<int *>(floatp); // error,不能使用static_cast在有类型指针内转换
    cout << *floatp << endl;    // out: 10.12
}

/**
 * （1）使用场景

用于将一个父类的指针/引用转化为子类的指针/引用（下行转换）。


（2）使用特点

基类必须要有虚函数，因为 dynamic_cast 是运行时类型检查，需要运行时类型信息，而这个信息是存储在类的虚函数表中。
对于下行转换，dynamic_cast 是安全的（当类型不一致时，转换过来的是空指针），而 static_cast 是不安全的。
对指针进行 dynamic_cast，失败返回 NULL，成功返回正常 cast 后的对象指针；对引用进行 dynamic_cast，失败抛出一个异常，成功返回正常 cast 后的对象引用。
 */
void testDynamicCast()
{
    //以下代码会有问题
    Parent *parent = new Parent();
    Child *child = dynamic_cast<Child*>(parent);
    child->getAge();

    Parent pobj;
    Parent &rPobj = pobj;
    Child &rChild = dynamic_cast<Child &>(rPobj);
    rChild.getAge();
}

/**
 * （1）使用场景

常量指针（或引用）与非常量指针（或引用）之间的转换。


（2）使用特点

cosnt_cast 是四种类型转换符中唯一可以对常量进行操作的转换符。
去除常量性是一个危险的动作，尽量避免使用。
 */
void testConstCast()
{
    //常量转非常量
    int a = 50;
    const int *b = &a;
    int *c = const_cast<int*>(b);
    cout<<*c<<endl;

    const int *d = const_cast<const int *>(c);
//    *e = 20;  不能修改常量
    cout<<*d<<endl;

    const int e = 100;
    const int &f = e;
    int &g = const_cast<int&>(f);
    cout<<g<<endl;
    const int &h = const_cast<const int &>(g);
    cout<<h<<endl;
}

/**
 * reinterpret 的英文含义有重新转换的含义，就相当于 C 语言中不相关类型的转换,强转。
 * （1）使用场景

用在任意指针（或引用）类型之间的转换。
能够将整型转换为指针，也可以把指针转换为整型或数组。


（2）使用特点

reinterpret_cast 是从底层对数据进行重新解释，依赖具体的平台，可移植性差。
不到万不得已，不用使用这个转换符，高危操作。
 */
void testReinterpretCast()
{
    int value = 100;
    // 1. 用在任意指针（或引用）类型之间的转换
    double *pd = reinterpret_cast<double *>(&value);
    cout << "*pd = " << *pd << endl;

    // 2. reinterpret_cast能够将指针值转化为整形值
    int *pv = &value;
    //int 不行，提示长度不够，无法转换
    uint64_t  pvaddr = reinterpret_cast<uint64_t>(pv);
    cout << "pvaddr = " << hex << pvaddr << endl;
    cout << "pv = " << pv << endl;
}